package server

import (
	"database/sql"
	"errors"
	"sieve_admin_server_userpass/lib/app"
	"sieve_admin_server_userpass/lib/config"
	"sieve_admin_server_userpass/lib/hash"
	"sieve_admin_server_userpass/lib/log"
	"sieve_admin_server_userpass/lib/rand"
	"sieve_admin_server_userpass/lib/util/convert"
	"sort"
	"sync"
	"time"
)

var (
	fAdmin = config.Ints("server.admin", []int{}, "管理员")
)

type mod_user struct{}

type adminUser struct {
	Uid      int
	Name     string
	RoleName string
	Leader   int
}

type adminUser_1 struct {
	Uid  int
	Name string
}

func (r *mod_user) API_query_search(ctx *Context) interface{} {
	List := make(map[string]interface{})
	List["Roles"] = GetRoles()
	List["Uids"] = GetAllUsers()
	return List
}
func (r *mod_user) API_query_list(ctx *Context) interface{} {
	var list []*adminUser = []*adminUser{}
	rows, err := db.Query("SELECT uid,roleName,name,Leader from app_user ")
	if err != nil {
		log.Err(err)
		return list
	}
	for rows.Next() {
		info := &adminUser{}
		err = rows.Scan(&info.Uid, &info.RoleName, &info.Name, &info.Leader)
		if err != nil {
			log.Err(err)
			continue
		}
		list = append(list, info)
	}
	return list

}

func (r *mod_user) API_add_user(ctx *Context) interface{} {
	_, err := db.Exec("INSERT INTO `app_user`(uid,roleName,name,Leader) VALUES(?,?,?,?)", ctx.Args.Get("Uid"), ctx.Args.Get("RoleName"), ctx.Args.Get("Name"), ctx.Args.Get("Leader"))
	if err != nil {
		return err
	}
	return "ok"
}

func (r *mod_user) API_edit_user(ctx *Context) interface{} {
	if ctx.Args.Get("Uid") == "" {
		return errors.New("error Request")
	}
	_, err := db.Exec("UPDATE `app_user` SET `roleName`=?,Leader=?  where `uid`=?", ctx.Args.Get("RoleName"), ctx.Args.Get("Leader"), ctx.Args.Get("Uid"))
	if err != nil {
		return err
	}
	return ctx.Args.Get("Uid")
}
func (r *mod_user) API_del_user(ctx *Context) interface{} {
	if ctx.Args.Get("Uid") == "" {
		return errors.New("error Request")
	}
	if ctx.Uid == convert.Atoi(ctx.Args.Get("Uid")) {
		return errors.New("不能删除自己")
	}
	_, err := db.Exec("DELETE FROM `app_user` where `uid`=?", ctx.Args.Get("Uid"))
	if err != nil {
		return err
	}
	return "OK"
}
func isAdmin(uid int) bool {
	for _, i := range *fAdmin {
		if uid == i {
			return true
		}
	}
	return false
}

func checkUserPerm(uid int, perm string) bool {

	return true
}

// func checkUserPerm(uid int, perm string) bool {
//	if isAdmin(uid) {
//		return true
//	}
//	u := GetUser(uid)
//	if u == nil {
//		return false
//	}
//	return u.HasPermission(perm)
// }

type User struct {
	Uid    int
	Name   string
	Title  string `json:",omitempty"`
	Leader int
}

func (u *User) HasPermission(perm string) bool {
	if isAdmin(u.Uid) {
		return true
	}
	perms, ok := rolePerm[u.Title]
	if !ok {
		return false
	}
	return perms[perm]
}
func GetAdminUser(uid int) *User {
	u := &User{Uid: uid}
	if err := superdb.QueryRow("SELECT `Name` FROM `admin_user` WHERE `Uid`=?", uid).Scan(&u.Name); err != nil {
		return nil
	}
	return u
}
func GetUser(uid int) *User {
	u := &User{Uid: uid}
	if err := db.QueryRow("SELECT `Name`,`roleName`,Leader FROM `app_user` WHERE `Uid`=?", uid).Scan(&u.Name, &u.Title, &u.Leader); err != nil {
		return nil
	}
	return u
}

func GetUsers() []*User {
	rows, err := db.Query("SELECT `Uid`,`Name`,`roleName`,`Leader` FROM `app_user`")
	if err != nil {
		return nil
	}
	defer rows.Close()

	var list []*User
	for rows.Next() {
		u := &User{}
		if err := rows.Scan(&u.Uid, &u.Name, &u.Title, &u.Leader); err != nil {
			return nil
		}
		list = append(list, u)
	}
	return list
}

func getLoginUid(usr, pwd string) (int, error) {
	var uid int
	var pwdHash string
	if err := superdb.QueryRow("SELECT `Uid`,`Password` FROM `admin_user` WHERE `Uid`=?", usr).Scan(&uid, &pwdHash); err != nil {
		if err == sql.ErrNoRows {
			return 0, errors.New("密码错误")
		} else {
			log.Err(err)
			return 0, errors.New("内部错误")
		}
	}
	if len(pwdHash) != 96 {
		return 0, errors.New("内部错误")
	}
	if hash.SHA256([]byte(pwd+pwdHash[64:])) != pwdHash[:64] {
		return 0, errors.New("密码错误")
	}
	return uid, nil
}
func GetAllUsers() []*adminUser_1 {
	list := []*adminUser_1{}
	rows, err := superdb.Query("SELECT `Uid`,`name` from `admin_user`")
	if err != nil {
		return list
	}
	defer rows.Close()
	for rows.Next() {
		info := &adminUser_1{}
		err = rows.Scan(&info.Uid, &info.Name)
		if err != nil {
			continue
		}
		list = append(list, info)
	}
	return list
}
func GenPwdHash(pwd string) string {
	salt := hash.MD5([]byte(rand.RandStr(16) + time.Now().String()))
	return hash.SHA256([]byte(pwd+salt)) + salt
}

var (
	sessions = map[int]*session{}
	sesslock = sync.Mutex{}
)

type session struct {
	Id         int
	Uid        int
	SessionKey string
	ExpireTime int64
}

func init() {
	AfterDbOpen(func() {
		if err := loadSessions(); err != nil {
			log.Fatal(err)
		}
		app.Async(func() {
			for {
				time.Sleep(time.Second)
				delExpireSession()
			}
		})
	})
}

func loadSessions() error {
	rows, err := db.Query("SELECT `id`,`Uid`,`SessionKey`,`ExpireTime` FROM `app_session`")
	if err != nil {
		return err
	}
	defer rows.Close()
	sesslock.Lock()
	defer sesslock.Unlock()
	sessions = map[int]*session{}
	for rows.Next() {
		sess := &session{}
		if err := rows.Scan(&sess.Id, &sess.Uid, &sess.SessionKey, &sess.ExpireTime); err != nil {
			return err
		}
		sessions[sess.Uid] = sess
	}
	return nil
}

func delExpireSession() {
	sesslock.Lock()
	defer sesslock.Unlock()
	now := time.Now().Unix()
	del := []*session{}
	for _, sess := range sessions {
		if now > sess.ExpireTime {
			del = append(del, sess)
		}
	}
	for _, sess := range del {
		delete(sessions, sess.Uid)
		db.Exec("DELETE FROM `app_session` WHERE `id`=?", sess.Id)
	}
}

func getSessionKey(uid int) string {
	sesslock.Lock()
	defer sesslock.Unlock()
	sess, ok := sessions[uid]
	if !ok {
		return ""
	}
	sess.ExpireTime = time.Now().Unix() + int64(*fSessExpire)
	db.Exec("UPDATE `app_session` SET `ExpireTime`=? WHERE `id`=?", sess.ExpireTime, sess.Id)
	return sess.SessionKey
}

func setSessionKey(uid int, skey string) error {
	sesslock.Lock()
	defer sesslock.Unlock()
	et := time.Now().Unix() + int64(*fSessExpire)
	if sess, ok := sessions[uid]; ok {
		if _, err := db.Exec("UPDATE `app_session` SET `SessionKey`=?,`ExpireTime`=? WHERE `id`=?", skey, et, sess.Id); err != nil {
			return err
		}
		sess.SessionKey = skey
		sess.ExpireTime = et
	} else {
		res, err := db.Exec("INSERT INTO `app_session` (`Uid`,`SessionKey`,`ExpireTime`) VALUES (?,?,?)", uid, skey, et)
		if err != nil {
			return err
		}
		id, _ := res.LastInsertId()
		sessions[uid] = &session{
			Id:         int(id),
			Uid:        uid,
			SessionKey: skey,
			ExpireTime: et,
		}
	}
	return nil
}

type UserTreeNode struct {
	User
	Followers []*UserTreeNode
}

func GetUserTree() (*UserTreeNode, error) {
	var tree *UserTreeNode
	m := map[int]*UserTreeNode{}
	for _, du := range GetUsers() {
		m[du.Uid] = &UserTreeNode{User: User{Uid: du.Uid, Name: du.Name, Title: du.Title, Leader: du.Leader}, Followers: []*UserTreeNode{}}
	}
	for _, du := range m {
		if du.Leader == 0 {
			if tree != nil {
				return nil, errors.New("部门数据错误：多个负责人")
			}
			tree = du
		} else {
			if l, ok := m[du.Leader]; ok {
				l.Followers = append(l.Followers, du)
			}
		}
	}
	if tree == nil {
		return nil, errors.New("部门数据错误：无负责人")
	}
	tree.Sort()
	return tree, nil
}

func (du *UserTreeNode) Sort() {
	if du.Followers == nil || len(du.Followers) == 0 {
		return
	}
	sort.Slice(du.Followers, func(i, j int) bool {
		return du.Followers[i].Uid < du.Followers[j].Uid
	})
	for _, f := range du.Followers {
		f.Sort()
	}
}

func (du *UserTreeNode) find(uid int) *UserTreeNode {
	if du.Uid == uid {
		return du
	}
	for _, f := range du.Followers {
		if u := f.find(uid); u != nil {
			return u
		}
	}
	return nil
}
